/*********************************************************************************
FileName: RingBuffCore.h

Description: Implementation des fonctions qui gerent le buffer circulaire.
			 -BufIn
			 -BufOut
			 -BufReInit
			 -BufResize

Authors: Vincent Leger et Francisco Jesus Ramos Reyes

Last Modification: 28-10-2012

Modifications: --
*********************************************************************************/

#include "RingBuffCore.h"


/*********************************************************************************
Function name : int BufIn(struct BufStruct *Buf, unsigned char *Data);
Brief: -Cette fonction gere les entree dans le buffer circulaire.
	   -Un index est maintenu en memoir pour connaitre l'emplacement memoire
	   	ou l'on peut commencer a ecrire du data.


Inputs: struct BufStruct *Buf --> Pointeur vers la structure BufStruct ou les
								  differantes information du buffer sont garde.
		unsigned char *Data)  --> Pointeur de la source qui contient le data
								  a mettre dans le buffer circulaire.
Outputs: int
Return value: int --> utilise pour le retour de code d'erreur

Last modified: 28-10-2012
notes: exemple d'utilisation et call out -- BufIn(&Buffer,BDev.WriteBuf+i);
*********************************************************************************/
int BufIn (struct BufStruct *Buf, unsigned char *Data)
{
	if (Buf->BufFull)
		return -1;
	Buf->BufEmpty = 0;
	DEBUG_CHARACTER("On the inside : ", *Data);
	Buf->Buffer[Buf->InIdx] = *Data;
	Buf->InIdx = (Buf->InIdx + 1) % Buf->BufSize;
	if (Buf->InIdx == Buf->OutIdx)
		Buf->BufFull = 1;
	return 0;
}

/*********************************************************************************
Function name : int BufOut(struct BufStruct *Buf, unsigned char *Data);
Brief: -Cette fonction gere les sortie dans le buffer circulaire.
	   -Un index est maintenu en memoir pour connaitre l'emplacement memoire
	   	du prochain element qui doit sortir du buffer.


Inputs: struct BufStruct *Buf --> Pointeur vers la structure BufStruct ou les
								  differantes information du buffer sont garde.
		unsigned char *Data)  --> Pointeur Pointeur de la destination ou
								  le data sort sera garde.
Outputs: int
Return value: int --> utilise pour le retour de code d'erreur

Last modified: 28-10-2012
notes: exemple d'utilisation et call out -- BufOut(&Buffer,BDev.ReadBuf+i);
*********************************************************************************/
int BufOut (struct BufStruct *Buf, unsigned char *Data)
{
	if (Buf->BufEmpty)
		return -1;
	Buf->BufFull = 0;
	*Data = Buf->Buffer[Buf->OutIdx];
	Buf->OutIdx = (Buf->OutIdx + 1) % Buf->BufSize;
	if (Buf->OutIdx == Buf->InIdx)
		Buf->BufEmpty = 1;
	return 0;
}

/*********************************************************************************
Function name : int BufReInit(struct BufStruct *Buf);
Brief: -Cette fonction est utilise pour faire la reinitialisation du buffer
		circulaire (valeur par defaut).
	   -La commande THEBUFFER_IOCTL_RESET dans buf_ioctl appelle cette
	    fonction.


Inputs: struct BufStruct *Buf --> Pointeur vers la structure BufStruct ou les
								  differantes information du buffer sont garde.

Outputs: int
Return value: int --> utilise pour le retour de code d'erreur

Last modified: 28-10-2012
notes: exemple d'utilisation et call out -- BufReInit(&Buffer);
*********************************************************************************/
int BufReInit(struct BufStruct *Buf)
{
    //reset all default values
    //BufResize(Buf, DEFAULT_BUFSIZE);  //DON'T... too long and we're clearing data anyways
    Buf->BufSize = DEFAULT_BUFSIZE;
    Buf->InIdx= 0;
    Buf->OutIdx = 0;
    Buf->BufFull = 0;
    Buf->BufEmpty = 1;
    kfree(Buf->Buffer);
    Buf->Buffer = (unsigned char*) kmalloc(DEFAULT_BUFSIZE * sizeof(unsigned char),0);
    if (IS_ERR(Buf->Buffer))
    {
        DEBUG_MESSAGE("The BUFFER IS IN BIG TROUBLE... PLEASE RE-INIT !");
    }
    memset(Buf->Buffer, 0, sizeof(char)*DEFAULT_BUFSIZE);
    return 0;
}

/*********************************************************************************
Function name : int BufResize(struct BufStruct *Buf, int newSize);
Brief: -Cette fonction sert a definir une nouvelle taille pour le buffer
		circulaire sans perdre de l'information.
	   -Si la nouvelle taille du buffer est plus petite que sa taille actuelle,
		une partie de l'information risque d'etre perdu.
	   -On ne peut pas allouer un espace memoire plus grand que le max absolu.
	   -La commande THEBUFFER_IOCTL_SET_BUFFERSIZE dans buf_ioctl appelle cette
	    fonction.


Inputs: struct BufStruct *Buf --> Pointeur vers la structure BufStruct ou les
								  differantes information du buffer sont garde.

Outputs: int
Return value: int --> utilise pour le retour de code d'erreur

Last modified: 28-10-2012
notes: exemple d'utilisation et call out -- BufResize(&Buffer, valueFromUser);
*********************************************************************************/
int BufResize(struct BufStruct *Buf, int newSize)
{
    unsigned short tmpIndex;
    unsigned short currentDataLength;
    char tmpBuffer[Buf->BufSize];

    for (tmpIndex=0;tmpIndex<Buf->BufSize;tmpIndex++)
        tmpBuffer[tmpIndex] = 0;

    if ((newSize < 1)||(newSize > MAX_BUFSIZE))
        newSize = DEFAULT_BUFSIZE;  //set default size or send ERROR ???

    tmpIndex = 0;
    while (Buf->OutIdx != Buf->InIdx)
    {
        tmpBuffer[tmpIndex] = Buf->Buffer[Buf->OutIdx];
        tmpIndex++;
        Buf->OutIdx = (Buf->OutIdx + 1) % Buf->BufSize;
    }
    currentDataLength = tmpIndex;
    //release mem for old buffer
    kfree(Buf->Buffer);
    //re-assign
    Buf->Buffer = (unsigned char*) kmalloc(newSize * sizeof(unsigned char),0);
    if (IS_ERR(Buf->Buffer))
    {
        DEBUG_MESSAGE("PANIC !!! The BUFFER IS IN BIG TROUBLE... PLEASE RE-INIT !");
    }
    Buf->BufSize = newSize;
    if (currentDataLength>newSize)
    {
        tmpIndex = currentDataLength - newSize;
        Buf->BufFull = 1;
        Buf->OutIdx = tmpIndex%newSize;
        Buf->InIdx = Buf->OutIdx;   //some way to do -1 without check for 0
    }
    else
    {
        tmpIndex = 0;
        Buf->OutIdx = 0;
        Buf->InIdx = currentDataLength;
        Buf->BufEmpty = 0;
        Buf->BufFull = 0;
        if (currentDataLength == 0)
        {
            Buf->BufEmpty = 1;
        }
        else if (Buf->OutIdx == Buf->InIdx)
        {
            Buf->BufFull = 1;
        }
    }

    while(tmpIndex<currentDataLength)
    {
        Buf->Buffer[tmpIndex%newSize] = tmpBuffer[tmpIndex];
        tmpIndex++;
    }

    return 0;
}
